#pragma once

#include <iostream>
#include <pthread.h>
#include <queue>
#include <unistd.h>
#include <time.h>
#include <cstdlib>

template<class T>
class BlockQueue
{
private:
    std::queue<T> _blockQueue;
    pthread_mutex_t _mtx;
    pthread_cond_t _p_cond;
    pthread_cond_t _c_cond;
    int _max_capacity;

private:
    bool isFull()
    {
        return _blockQueue.size() == _max_capacity;
    }
    bool isEmpty()
    {
        return _blockQueue.size() == 0;
    }
public:
    BlockQueue(int max_capacity)
        : _max_capacity(max_capacity)
    {}
    void bqInit()
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
    }
    void bqPop(T *out)
    {
        pthread_mutex_lock(&_mtx);
        while (isEmpty())
        {
            pthread_cond_wait(&_c_cond, &_mtx);
        }
        // 非空、被唤醒
        *out = _blockQueue.front();
        _blockQueue.pop();

        pthread_mutex_unlock(&_mtx);

        pthread_cond_signal(&_p_cond);
    }
    void bqEqueue(const T& in)
    {
        pthread_mutex_lock(&_mtx);
        while (isFull())
        {
            pthread_cond_wait(&_p_cond, &_mtx);
        }
        // 非满：空或者不满、或者被唤醒
        _blockQueue.push(in);

        pthread_mutex_unlock(&_mtx);

        pthread_cond_signal(&_c_cond);
    }
    ~BlockQueue(){}
};